package com.orchidea.uml.service.update {
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.net.URLRequest;
import flash.net.URLStream;
import flash.desktop.NativeApplication;
import flash.desktop.Updater;
import flash.utils.ByteArray;

import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;

public class UpdateManager extends EventDispatcher{
    public var versionURL:String;

    public var isUpdate:Boolean = false;

    public var isLoaded:Boolean = false;

    private var appXml:XML = NativeApplication.nativeApplication.applicationDescriptor;

    private var currentVersion:String = appXml.@version;

    private var version:XML;

    private var urlStream:URLStream;

    private var fileData:ByteArray = new ByteArray();

    private var versionService:HTTPService;

    public function UpdateManager(vURL:String):void {
        versionURL = vURL;
        loadRemoteFile();
    }

    /**
     * Load the remote version.xml file
     */
    private function loadRemoteFile():void {
        versionService = new HTTPService();
        versionService.url = this.versionURL;
        versionService.useProxy = false;
        versionService.method = "GET";
        versionService.resultFormat = "xml";
        versionService.send();
        versionService.addEventListener(ResultEvent.RESULT, testVersion);
    }

    /**
     * Test the currentVersion against the remote version file and either alert the user of
     * an update available or force the update
     */
    public function testVersion(event:ResultEvent):void
    {
        version = XML(event.result);
        versionService.removeEventListener(ResultEvent.RESULT, testVersion);

        if (version.@forceUpdate != undefined)
        {
            isLoaded = true;
            if ((currentVersion != version.@version) && version.@forceUpdate == true) {
                getUpdate();
            } else if (currentVersion != version.@version) {
                Alert.show("There is an update available,\nwould you like to get it now? \n\nDetails:\n" + version.@message, "Choose Yes or No", 3, null, alertClickHandler);
            }
        }
        else
        {
            dispatchEvent(new Event("updaterComplete"));
        }
    }

    /**
     * Test the currentVersion against the remote version file and either alert the user of
     * an update available or force the update, if no update available, alert user
     */
    public function checkForUpdate():Boolean
    {
        if (version == null) {
            this.loadRemoteFile();
            return true;
        }

        if ((currentVersion != version.@version) && version.@forceUpdate == true) {
            getUpdate();
        } else if (currentVersion != version.@version) {
            Alert.show("There is an update available,\nwould you like to get it now? \n\nDetails:\n" + version.@message, "Choose Yes or No", 3, null, alertClickHandler);
        } else {
            Alert.show("There are no new updates available", "NOTICE");
        }
        return true;
    }

    // handle the Alert window decission
    private function alertClickHandler(event:CloseEvent):void {
        if (event.detail == Alert.YES) {
            getUpdate();
        }
    }

    // get the new version from the remote server
    public function getUpdate():void {
        dispatchEvent(new Event("isUpdating"));
        var urlReq:URLRequest = new URLRequest(version.@downloadLocation);
        urlStream = new URLStream();
        urlStream.load(urlReq);
        urlStream.addEventListener(Event.COMPLETE, loaded);
    }

    // read in the new AIR package
    private function loaded(event:Event):void {
        urlStream.readBytes(fileData, 0, urlStream.bytesAvailable);
        urlStream.removeEventListener(Event.COMPLETE, loaded);
        writeAirFile();
    }

    // write the newly downloaded AIR package to the application storage directory
    private function writeAirFile():void {
        var file:File = File.applicationStorageDirectory.resolvePath("update.air");
        var fileStream:FileStream = new FileStream();
        fileStream.addEventListener(Event.CLOSE, fileClosed);
        fileStream.openAsync(file, FileMode.WRITE);
        fileStream.writeBytes(fileData, 0, fileData.length);
        fileStream.close();
    }

    // after the write is complete, call the update method on the Updater class
    private function fileClosed(event:Event):void
    {
        var updater:Updater = new Updater();
        var airFile:File = File.applicationStorageDirectory.resolvePath("update.air");
        updater.update(airFile, version.@version);
    }

}

}